import java.awt.*;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.swing.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;



public class FileEncrypter extends JFrame{
    public static void main(String[] args) {
        FileEncrypter fe = new FileEncrypter();
        fe.show();
    }

    FileEncrypter(){
        this.setSize(550,200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocation(400,300);
        this.setTitle("3DES加密工具");
        Container c = this.getContentPane();
        c.setLayout(new FlowLayout());
        JLabel label = new JLabel("选择文件");
        c.add(label);
        final JTextField fileText = new JTextField(35);
        c.add(fileText);

        JButton chooseButton = new JButton("浏览");
        chooseButton.addActionListener(new ActionListener(){
            //浏览按钮的点击事件监听
            @Override
            public void actionPerformed(ActionEvent e){
                JFileChooser chooser = new JFileChooser();
                chooser.setCurrentDirectory(new File("."));
                int result = chooser.showOpenDialog(null);
                if(result == JFileChooser.APPROVE_OPTION){
                    //获得文件绝对路径
                    String path = chooser.getSelectedFile().getAbsolutePath();
                    fileText.setText(path);
                }
            }
        });

        c.add(chooseButton);
        JLabel label2 = new JLabel("秘钥(24个字符):");
        c.add(label2);
        final JTextField keyText = new JTextField(35);
        c.add(keyText);
        JButton jbe = new JButton("加密");
        c.add(jbe);
        jbe.addActionListener(new ActionListener(){
            //以下编写"加密"按钮的监听和事件
            @Override
            public void actionPerformed(ActionEvent event) {
                String wenjian,miyao;
                wenjian = fileText.getText();
                miyao = keyText.getText();
                if("".equals(wenjian) || wenjian == null){
                    JOptionPane.showMessageDialog(null,"请选择文件！","提示",JOptionPane.OK_OPTION);
                }else{
                    if("".equals(miyao) || miyao == null){
                        JOptionPane.showMessageDialog(null,"请输入24字节秘钥！","提示",JOptionPane.OK_OPTION);
                    }else{
                        if(miyao.length() != 24){
                            JOptionPane.showMessageDialog(null, "秘钥必须为24字节！","提示",JOptionPane.OK_OPTION);
                        }else{
                            //将三个秘钥分别 存入三个字节型数组中
                            byte[] key1 = miyao.substring(0,8).getBytes();
                            byte[] key2 = miyao.substring(8,16).getBytes();
                            byte[] key3 = miyao.substring(16,24).getBytes();

                            File file = new File(wenjian);
                            //读取明文并存入字节型数组plain中
                            byte[] plain = bytefromfile(file);

                            try {
                                byte[] bytOut = encryptByDES(decryptByDES(encryptByDES(plain,key1),key2),key1);
                                String fileOut = wenjian + ".tdes";
                                FileOutputStream fos = new FileOutputStream(fileOut);
                                for(int i = 0; i < bytOut.length; i++){
                                    fos.write((int)bytOut[i]);
                                }
                                fos.close();
                                JOptionPane.showMessageDialog(null,"加密成功!","提示",JOptionPane.INFORMATION_MESSAGE);
                            } catch (Exception e) {
                                //e.printStackTrace();
                                JOptionPane.showMessageDialog(null,"加密失败!请检查文件或者秘钥","提示",JOptionPane.OK_OPTION);
                            }

                        }
                    }
                }
            }

        });


        JButton jbD = new JButton("解密");
        c.add(jbD);
        //解密按钮点击事件
        jbD.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent arg0) {
                String wenjian,wenjian1,miyao;
                wenjian = fileText.getText();
                miyao = keyText.getText();
                if("".equals(wenjian) || wenjian == null){
                    JOptionPane.showMessageDialog(null,"请选择文件！","提示",JOptionPane.OK_OPTION);
                    return;
                }
                if(wenjian.substring(wenjian.length() - 5).toLowerCase().equals(".tdes")){
                    if(miyao.length()!=24){
                        JOptionPane.showMessageDialog(null, "秘钥必须为24字节！","提示",JOptionPane.OK_OPTION);
                        return;
                    }else{
                        wenjian1 = wenjian.substring(0,wenjian.length() - 5);
                        JFileChooser chooser = new JFileChooser();
                        chooser.setCurrentDirectory(new File("."));
                        //用户指定要保存的文件的位置
                        chooser.setSelectedFile(new File(wenjian1));
                        int ret = chooser.showSaveDialog(null);
                        if(ret == 0){
                            byte[] key1 = miyao.substring(0,8).getBytes();
                            byte[] key2 = miyao.substring(8,16).getBytes();
                            byte[] key3 = miyao.substring(16,24).getBytes();

                            File file = new File(wenjian);
                            //读取密文
                            byte[] miwen = bytefromfile(file);
                            try{
                                //解密
                                byte[] bytOut = decryptByDES(encryptByDES(decryptByDES(miwen,key1),key2),key1);

                                File fileOut = chooser.getSelectedFile();
                                fileOut.createNewFile();
                                FileOutputStream fos = new FileOutputStream(fileOut);

                                for(int i = 0; i < bytOut.length; i++){
                                    fos.write((int) bytOut[i]);
                                }

                                fos.close();
                                JOptionPane.showMessageDialog(null, "解密成功！","提示",JOptionPane.INFORMATION_MESSAGE);

                            }catch (Exception e) {
                                JOptionPane.showMessageDialog(null, "解密失败！请检查文件或秘钥","提示",JOptionPane.OK_OPTION);
                            }


                        }
                    }
                }else{
                    JOptionPane.showMessageDialog(null, "不是合法的加密文件！","提示",JOptionPane.OK_OPTION);
                }
            }

        });



    }


    //从输入的文件中读取字节，保存于TextofFile数组中，并返回
    private byte[] bytefromfile(File filein){
        byte[] TextofFile = new byte[(int)filein.length()];
        try{
            FileInputStream fin = new FileInputStream(filein);
            for(int i = 0; i < filein.length(); i++){
                TextofFile[i] = (byte)fin.read();
            }
            fin.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        return TextofFile;
    }

    //根据输入的明文进行加密
    private byte[] encryptByDES(byte[] bytP, byte[] bytKey) throws Exception{
        DESKeySpec desKS = new DESKeySpec(bytKey);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
        SecretKey sk = skf.generateSecret(desKS);
        Cipher cip = Cipher.getInstance("DES");
        cip.init(Cipher.ENCRYPT_MODE, sk);
        return cip.doFinal(bytP);
    }

    //根据密文和秘钥进行解密
    private byte[] decryptByDES(byte[] bytE, byte[] bytKey) throws Exception{
        DESKeySpec desKS = new DESKeySpec(bytKey);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
        SecretKey sk = skf.generateSecret(desKS);
        Cipher cip = Cipher.getInstance("DES");
        cip.init(Cipher.DECRYPT_MODE, sk);
        return cip.doFinal(bytE);
    }


}